#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
#Current folder
cur_dir=`pwd`

# Get public IP address
IP=$(ip addr | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | egrep -v "^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\." | head -n 1)
if [[ "$IP" = "" ]]; then
    IP=$(wget -qO- -t1 -T2 ipv4.icanhazip.com)
fi
# Get public IP interface
line=$(expr $(ifconfig|grep "$IP" -n|awk -F: '{print $1}') - 1 )
IPHW=$(ifconfig|sed -n "$line p"|awk '{print $1}')

# Make sure only root can run our script
function rootness(){
    if [[ $EUID -ne 0 ]]; then
       echo "Error:This script must be run as root!" 1>&2
       exit 1
    fi
}

# Check OS
function checkos(){
    if [ -f /etc/redhat-release ];then
        OS='CentOS'
    else
        echo "Not support OS, Please reinstall OS and retry!"
        exit 1
    fi
}

# Get version
function getversion(){
    if [[ -s /etc/redhat-release ]];then
        grep -oE  "[0-9.]+" /etc/redhat-release
    else
        grep -oE  "[0-9.]+" /etc/issue
    fi
}

# CentOS version
function centosversion(){
    local code=$1
    local version="`getversion`"
    local main_ver=${version%%.*}
    if [ $main_ver == $code ];then
        return 0
    else
        return 1
    fi
}

# Disable selinux
function disable_selinux(){
if [ -s /etc/selinux/config ] && grep 'SELINUX=enforcing' /etc/selinux/config; then
    sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
    setenforce 0
	clear
fi
}

#Non native IP binding support
function binding_support(){
cat /etc/sysctl.conf|grep "net.ipv4.ip_nonlocal_bind"
	if [ $? == 1 ];then
cat>>/etc/sysctl.conf<<EOF
net.ipv4.ip_nonlocal_bind=1
EOF
	else
sed -i '/net.ipv4.ip_nonlocal_bind/d' /etc/sysctl.conf
cat>>/etc/sysctl.conf<<EOF
net.ipv4.ip_nonlocal_bind=1
EOF
	fi
	sysctl -p
	clear
}

# Pre-installation settings
function keepha_install(){
 # Set keepalived config notification_email
    echo "Please input notification_email for keepalived:"
    read -p "(Default notification_email: name@email.com):" notificationemail
    [ -z "$notificationemail" ] && notificationemail="name@email.com"
    echo ""
	
	function add_other_notification_email(){
    printf "Input other notification_email for keepalived? (y/n) "
    printf "\n"
    read -p "(Default: n):" answer
    if [ -z $answer ]; then
        answer="n"
    fi
	
    if [ "$answer" = "y" ]; then
		echo "Please input notification_email for keepalived:"
		read -p "(Default notification_email: name@email.com):" notificationemail1
		[ -z "$notificationemail1" ] && notificationemail1="name@email.com"
		echo ""
    fi
	}
	add_other_notification_email
	
 # Set keepalived config notification_email_from
    echo "Please input notification_email_from for keepalived:"
    read -p "(Default notification_email_from: name@email.com):" notificationemailfrom
    [ -z "$notificationemailfrom" ] && notificationemailfrom="name@email.com"
	echo ""
	
 # Set keepalived config interface
    echo "Please input interface for keepalived:"
    read -p "(Default interface: $IPHW):" interface
    [ -z "$interface" ] && interface="$IPHW"
	echo ""
	
 # Set keepalived config virtual_router_id
    echo "Please input virtual_router_id for keepalived:"
    read -p "(Default virtual_router_id: 50):" virtualrouterid
    [ -z "$virtualrouterid" ] && virtualrouterid="50"
	echo ""
	
 # Set keepalived config auth_pass
    echo "Please input auth_pass for keepalived:"
    read -p "(Default auth_pass: password):" authpass
    [ -z "$authpass" ] && authpass="password"
	echo ""
	
 # Check keepalived Master
    printf "This Server is Master? (y/n) "
    printf "\n"
    read -p "(Default: y):" answer
    if [ -z $answer ]; then
        answer="y"
    fi
    if [ "$answer" = "y" ]; then
        state="MASTER"
		priority="101"
    else
        state="BACKUP"
		priority="100"
    fi

 # Set keepalived config virtual_ipaddress
    echo "Please input virtual_ipaddress for keepalived:"
    read -p "(Default virtual_ipaddress: 192.168.0.100 ):" virtualipaddress
    [ -z "$virtualipaddress" ] && virtualipaddress="192.168.0.100"
	echo ""
	
 # Set HAproxy config stats_port
    echo "Please input stats_port for HAProxy:"
    read -p "(Default stats_port: 8080 ):" statsport
    [ -z "$statsport" ] && statsport="8080"
	echo ""

 # Set HAproxy config auth_user
    echo "Please input auth_user for HAProxy:"
    read -p "(Default auth_user: admin ):" hauthuser
    [ -z "$hauthuser" ] && hauthuser="admin"
	echo ""

 # Set HAproxy config auth_pass
    echo "Please input auth_pass for HAProxy:"
    read -p "(Default auth_pass: password):" hauthpass
    [ -z "$hauthpass" ] && hauthpass="password"
	echo ""
	
 # Set HAproxy config APP_listen_NAME
    echo "Please input APP_NAME for HAProxy:"
    read -p "(Default APP_NAME: demo ):" appname
    [ -z "$appname" ] && appname="demo"
	echo ""

 # Set HAproxy config APP_listen_PORT
    echo "Please input APP_listen_PORT for HAProxy:"
    read -p "(Default APP_PORT: 80 ):" appport
    [ -z "$appport" ] && appport="80"
	echo ""
	
 # Set HAproxy config APP_listen_MODE
    echo "Please input APP_listen_MODE for HAProxy:"
    read -p "(tcp or http,Default APP_MODE: tcp):" appmode
    [ -z "$appmode" ] && appmode="tcp"
	echo ""
	
 # Set HAproxy config APP_SERVER1
    echo "Please input APP_SERVER1 for HAProxy:"
    read -p "(Default APP_SERVER1: 192.168.0.2 ):" appserver1
    [ -z "$appserver1" ] && appserver1="192.168.0.2"
	echo ""
	
 # Set HAproxy config APP_SERVER1_PORT
    echo "Please input APP_SERVER1_PORT for HAProxy:"
    read -p "(Default APP_SERVER1_PORT: 80 ):" appserver1port
    [ -z "$appserver1port" ] && appserver1port="80"
	echo ""
	
 # Set HAproxy config APP_SERVER2
    echo "Please input APP_SERVER2 for HAProxy:"
    read -p "(Default APP_SERVER2: 192.168.0.3 ):" appserver2
    [ -z "$appserver2" ] && appserver2="192.168.0.3"
	echo ""
	
 # Set HAproxy config APP_SERVER2_PORT
    echo "Please input APP_SERVER2_PORT for HAProxy:"
    read -p "(Default APP_SERVER2_PORT: 80 ):" appserver2port
    [ -z "$appserver2port" ] && appserver2port="80"
	echo ""
			
#yum install
	yum install -y haproxy keepalived 
	chkconfig haproxy on
	chkconfig keepalived on
	clear
}

# config keepalived.conf
function keepalived(){
rm -f /etc/keepalived/keepalived.conf
cat>>/etc/keepalived/keepalived.conf<<EOF
 ! Configuration File for keepalived

global_defs {
   notification_email {
     $notificationemail
   }
   notification_email_from $notificationemailfrom
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL
}

vrrp_script chk_haproxy {  
    script "killall -0 haproxy"  
    interval 2  
    weight 2  
}

vrrp_instance VI_1 {
    state $state
    interface $IPHW
    virtual_router_id $virtualrouterid
    priority $priority
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass $authpass
    }
    virtual_ipaddress {
        $virtualipaddress
    }
	track_script {  
		chk_haproxy  
    }  
  
    #状态通知  
    notify_master "/etc/keepalived/Mailnotify.py master"  
    notify_backup "/etc/keepalived/Mailnotify.py backup"  
    notify_fault "/etc/keepalived/Mailnotify.py fault"  
}
EOF
}


# config haproxy.cfg
function haproxy(){
rm -f /etc/haproxy/haproxy.cfg
cat>>/etc/haproxy/haproxy.cfg<<EOF
global
    log         127.0.0.1 local1 notice
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     65536
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
    mode                    http
    log                     global
    option                  dontlognull
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 65535

listen stats_auth *:$statsport
        stats enable  
        stats uri  /status #管理地址  
        stats auth  $hauthuser:$hauthpass #管理帐号:管理密码  
        stats admin if TRUE
#		stats hide-version

listen  $appname   *:$appport
        mode $appmode
        maxconn 65536
        balance roundrobin
		server $appserver1 $appserver1:$appserver1port check inter 5000 fall 1 rise 2
		server $appserver2 $appserver2:$appserver2port check inter 5000 fall 1 rise 2
EOF
}


# config Mailnotify.py
function mailnotify(){
yum install -y python
pypath=$(whereis python|awk '{print $2}')
rm -f /etc/keepalived/Mailnotify.py
cat>>/etc/keepalived/Mailnotify.py<<EOF
    #!$pypath
    #coding: utf-8  
    from email.MIMEMultipart import MIMEMultipart  
    from email.MIMEText import MIMEText  
    from email.MIMEImage import MIMEImage  
    from email.header import Header  
    import sys  
    import smtplib  
      
    #---------------------------------------------------------------  
    # Name:        Mailnotify.py  
    # Purpose:     Mail notify to SA  
    # Author:      Liutiansi  
    # Email:       liutiansi@gamil.com  
    # Created:     2011/03/09  
    # Copyright:   (c) 2011  
    #--------------------------------------------------------------  
    strFrom = '$notificationemailfrom'  
    strTo = '$notificationemail'  
    smtp_server='127.0.0.1'  
    smtp_pass=''  
      
    if sys.argv[1]!="master" and sys.argv[1]!="backup"  and sys.argv[1]!="fault":  
        sys.exit()  
    else:  
        notify_type=sys.argv[1]  
      
      
    mail_title='[紧急]负载均衡器邮件通知'  
    mail_body_plain=notify_type+'被激活，请做好应急处理。'  
    mail_body_html='<b><font color=red>'+notify_type+'被激活，请做好应急处理。</font></b>'  
      
    msgRoot = MIMEMultipart('related')  
    msgRoot['Subject'] =Header(mail_title,'utf-8')  
    msgRoot['From'] = strFrom  
    msgRoot['To'] = strTo  
      
    msgAlternative = MIMEMultipart('alternative')  
    msgRoot.attach(msgAlternative)  
      
    msgText = MIMEText(mail_body_plain, 'plain', 'utf-8')  
    msgAlternative.attach(msgText)  
      
      
    msgText = MIMEText(mail_body_html, 'html','utf-8')  
    msgAlternative.attach(msgText)  
      
      
    smtp = smtplib.SMTP()  
    smtp.connect(smtp_server)  
    smtp.login(smtp_user,smtp_pass)  
    smtp.sendmail(strFrom, strTo, msgRoot.as_string())  
    smtp.quit()  
EOF
}

 # Echo keepalived config 
function echo_config(){
	clear
    echo ""
    echo "---------------------------"
    echo "keepalived notification_email = $notificationemail $notificationemail1"
    echo "keepalived notification_email_from = $notificationemailfrom"
	echo "keepalived VRRP_Interface = $interface"
	echo "keepalived state = $state"
	echo "keepalived virtual_router_id=$virtualrouterid"
	echo "keepalived auth_pass=$authpass"
	echo "keepalived virtual_ipaddress=$virtualipaddress"
    echo "---------------------------"
	echo "HAProxy stats_port=$statsport"
	echo "HAProxy auth_user=$hauthuser"
	echo "HAProxy auth_pass=$hauthpass"
	echo "HAProxy APP_NAME=$appname"
	echo "HAProxy APP_PORT=$appport"
	echo "HAProxy APP_MODE=$appmode"
	echo "HAProxy APP_SERVER1=$appserver1:$appserver1port"
	echo "HAProxy APP_SERVER2=$appserver2:$appserver2port"
    echo ""
    echo "---------------------------"
	echo "HAProxy Status URL: http://$virtualipaddress:$statsport/status"
}

 # start service
function startservice(){
	clear
	service keepalived restart
	service haproxy restart
	clear
}

# Pre-installation settings
function pre_install(){
    # Not support CentOS 5
    if centosversion 5; then
        echo "Not support CentOS 5.x, please change OS to CentOS 6,7/Debian/Ubuntu and retry."
        exit 1
    fi
    # Set ShadowsocksR config password
    echo "Please input password for ShadowsocksR:"
    read -p "(Default password: password):" shadowsockspwd
    [ -z "$shadowsockspwd" ] && shadowsockspwd="password"
    echo ""
    echo "---------------------------"
    echo "password = $shadowsockspwd"
    echo "---------------------------"
    echo ""
    # Set ShadowsocksR config port
    while true
    do
    echo -e "Please input port for ShadowsocksR [1-65535]:"
    read -p "(Default port: 8989):" shadowsocksport
    [ -z "$shadowsocksport" ] && shadowsocksport="8989"
    expr $shadowsocksport + 0 &>/dev/null
    if [ $? -eq 0 ]; then
        if [ $shadowsocksport -ge 1 ] && [ $shadowsocksport -le 65535 ]; then
            echo ""
            echo "---------------------------"
            echo "port = $shadowsocksport"
            echo "---------------------------"
            echo ""
            break
        else
            echo "Input error! Please input correct number."
        fi
    else
        echo "Input error! Please input correct number."
    fi
    done
    get_char(){
        SAVEDSTTY=`stty -g`
        stty -echo
        stty cbreak
        dd if=/dev/tty bs=1 count=1 2> /dev/null
        stty -raw
        stty echo
        stty $SAVEDSTTY
    }
    echo ""
    echo "Press any key to start...or Press Ctrl+C to cancel"
    char=`get_char`
    # Install necessary dependencies
    if [ "$OS" == 'CentOS' ]; then
        yum install -y wget unzip openssl-devel gcc swig python python-devel python-setuptools autoconf libtool libevent
        yum install -y m2crypto automake make curl curl-devel zlib-devel perl perl-devel cpio expat-devel gettext-devel
    else
        apt-get -y update
        apt-get -y install python python-dev python-pip python-m2crypto curl wget unzip gcc swig automake make perl cpio build-essential
    fi
    cd $cur_dir
}

# Download files
function download_files(){
    # Download libsodium file
    if ! wget --no-check-certificate -O libsodium-1.0.8.tar.gz https://github.com/jedisct1/libsodium/releases/download/1.0.8/libsodium-1.0.8.tar.gz; then
        echo "Failed to download libsodium file!"
        exit 1
    fi
    # Download ShadowsocksR file
    if ! wget --no-check-certificate -O manyuser.zip https://github.com/breakwa11/shadowsocks/archive/manyuser.zip; then
        echo "Failed to download ShadowsocksR file!"
        exit 1
    fi
    # Download ShadowsocksR chkconfig file
    if [ "$OS" == 'CentOS' ]; then
        if ! wget --no-check-certificate https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocksR -O /etc/init.d/shadowsocks; then
            echo "Failed to download ShadowsocksR chkconfig file!"
            exit 1
        fi
    else
        if ! wget --no-check-certificate https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocksR-debian -O /etc/init.d/shadowsocks; then
            echo "Failed to download ShadowsocksR chkconfig file!"
            exit 1
        fi
    fi
}

# Config ShadowsocksR
function config_shadowsocks(){
    cat > /etc/shadowsocks.json<<-EOF
{
    "server":"0.0.0.0",
    "server_ipv6":"::",
    "server_port":${shadowsocksport},
    "local_address":"127.0.0.1",
    "local_port":1080,
    "password":"${shadowsockspwd}",
    "timeout":120,
    "method":"aes-256-cfb",
    "protocol":"origin",
    "protocol_param":"",
    "obfs":"plain",
    "obfs_param":"",
    "redirect":"",
    "dns_ipv6":false,
    "fast_open":false,
    "workers":1
}
EOF
}

# Install ShadowsocksR
function install_ss(){
    # Install libsodium
    tar zxf libsodium-1.0.8.tar.gz
    cd $cur_dir/libsodium-1.0.8
    ./configure && make && make install
    ldconfig
    # Install ShadowsocksR
    cd $cur_dir
    unzip -q manyuser.zip
    mv shadowsocks-manyuser/shadowsocks /usr/local/
    if [ -f /usr/local/shadowsocks/server.py ]; then
        chmod +x /etc/init.d/shadowsocks
        # Add run on system start up
        if [ "$OS" == 'CentOS' ]; then
            chkconfig --add shadowsocks
            chkconfig shadowsocks on
        else
            update-rc.d shadowsocks defaults
        fi
        # Run ShadowsocksR in the background
        /etc/init.d/shadowsocks start
        clear
        echo ""
        echo "Congratulations, ShadowsocksR install completed!"
        echo -e "Server IP: \033[41;37m ${IP} \033[0m"
        echo -e "Server Port: \033[41;37m ${shadowsocksport} \033[0m"
        echo -e "Password: \033[41;37m ${shadowsockspwd} \033[0m"
        echo -e "Local IP: \033[41;37m 127.0.0.1 \033[0m"
        echo -e "Local Port: \033[41;37m 1080 \033[0m"
        echo -e "Protocol: \033[41;37m origin \033[0m"
        echo -e "obfs: \033[41;37m plain \033[0m"
        echo -e "Encryption Method: \033[41;37m aes-256-cfb \033[0m"
        echo ""
        echo "If you want to change protocol & obfs, reference URL:"
        echo "https://github.com/breakwa11/shadowsocks-rss/wiki/Server-Setup"
        echo ""
        echo "Enjoy it!"
        echo ""
    else
        echo "Shadowsocks install failed! "
        install_cleanup
        exit 1
    fi
}

# Install cleanup
function install_cleanup(){
    cd $cur_dir
    rm -f manyuser.zip
    rm -rf shadowsocks-manyuser
    rm -f libsodium-1.0.8.tar.gz
    rm -rf libsodium-1.0.8
}


# Uninstall ShadowsocksR
function uninstall_shadowsocks(){
    printf "Are you sure uninstall ShadowsocksR? (y/n) "
    printf "\n"
    read -p "(Default: n):" answer
    if [ -z $answer ]; then
        answer="n"
    fi
    if [ "$answer" = "y" ]; then
        /etc/init.d/shadowsocks status > /dev/null 2>&1
        if [ $? -eq 0 ]; then
            /etc/init.d/shadowsocks stop
        fi
        checkos
        if [ "$OS" == 'CentOS' ]; then
            chkconfig --del shadowsocks
        else
            update-rc.d -f shadowsocks remove
        fi
        rm -f /etc/shadowsocks.json
        rm -f /etc/init.d/shadowsocks
        rm -rf /usr/local/shadowsocks
        echo "ShadowsocksR uninstall success!"
    else
        echo "uninstall cancelled, Nothing to do"
    fi
}

# Install ShadowsocksR
function install_shadowsocks(){
    checkos
    rootness
    disable_selinux
    pre_install
    download_files
    config_shadowsocks
    install_ss
    install_cleanup
}

# Install HAproxy
function install_all(){
    checkos
	rootness
    disable_selinux
	binding_support
	keepha_install
	keepalived
	haproxy
	mailnotify
	startservice
	echo_config
}

# Uninstall HAproxy
function uninstall_all(){
	yum remove -y keepalived haproxy
	rm /etc/haproxy/ -rf
	rm /etc/keepalived/ -rf
	clear
	echo "Everything is removed!"
}

# Initialization step
action=$1
[  -z $1 ] && action=help
case "$action" in
installha)
    install_all
    ;;
uninstallha)
    uninstall_all
    ;;
installss)
    install_shadowsocks
    ;;
uninstallss)
    uninstall_shadowsocks
    ;;
*)
    echo "Usage: `basename $0` {installss|uninstallss|installha|uninstallha}"
	echo ""
	echo "To Install shadowsocks use installss"
	echo "To Uninstall shadowsocks use installss"
	echo "To Install HAProxy & Keepalived use installha"
	echo "To Uninstall HAProxy & Keepalived use uninstallha"

    ;;
esac
